package edu.uclm.combTest.core.aetg;

import edu.uclm.combTest.core.Algorithm;
import edu.uclm.combTest.core.Combination;
import edu.uclm.combTest.core.Set;
import edu.uclm.combTest.core.pairwise.Pair;
import edu.uclm.combTest.core.pairwise.PairsTable;

public class AETGAlgorithm extends Algorithm {

	public void buildCombinations() {
		///verbose("Building pair tables:");
		this.pairsTables=buildPairTables();

		// ajout de la combinaison (0,0,0,0,...)
		Combination c=this.getCombination(0);
		c.updateIndex(this.divisors);
		///verbose("<li><b>Adding combination #0 : " + c.toString() + "</b>");
		c.visitPairs(this.pairsTables);

		this.selectedPositions.add(0);
		Combination aux=null;
		///@SuppressWarnings("unused")
		long selectedPos=0;
		//int iteracion=0;
		while (getPairWithWeight0(pairsTables)!=null) {
			//System.out.println(iteracion++);
			long MAX;
			///verbose("<li>Building new combination");
			// selection du premier parametre de la nouvelle combinaison
			Combination selected = initializeNewCombination();
			///verbose("<ol><li>Initial element positions: " + selected.toStringPositions()+"</li>");
			// on détermine les autres parametres.
			for (int i=0; i<this.sets.size(); i++) {
				// si la position n'est pas encore trouvée
				if (selected.getPosition(i)==-1) {
					Set set=(Set)this.sets.get(i);
					MAX=Long.MIN_VALUE;
					// on trouve l'élément qui est le moins utilisé
					// parcours de tous les sets
					for (int j=0; j<set.size(); j++) {
						//System.out.println("\t\t" + j);
						// copie la selection actuelle
						aux=copy(selected);
						// tente une modification
						aux.setValuePosition(i, j);
						// évalue le nouveau poid : le nouveau nombre de pair visité.
						int pairsVisited=getPairsVisited(aux, i);
						// si le poid est avantageux, on le garde.
						if (pairsVisited>MAX) {
							MAX=pairsVisited;
							selectedPos=j;
						}
					}
					// aux a bouger, on le remet a la bonne valeur
					aux.setValuePosition(i, selectedPos);
					selected=copy(aux);
					///verbose("<li>Modified position #" + selectedPos + ": " + selected.toStringPositions()+"</li>");
				}
			}
			selected.updateIndex(this.divisors);
			///verbose("<li>" + selected.toStringPositions() + " corresponds to combination #" + selected.getIndex() +
			//		" (" + this.getCombination(selected.getIndex()).toString() + ").");
			///verbose(" <b>" + this.getCombination(selected.getIndex()).toString() + " added.</b><br>");
			///verbose("Visiting pairs:");
			selected.visitPairs(this.pairsTables);
			//System.out.println(selected.toStringPositions());
			///verbose(this.showHTMLPairsTables());
			this.selectedPositions.add(selected.getIndex());
		}
	}

	/**
	 * première étape, trouver l'élément qui est le plus présent dans les paires non visitées.
	 * @return
	 */
	private Combination initializeNewCombination() {
		Combination selected=new Combination(this.sets.size());
		for (int i=0; i<this.sets.size(); i++)
			selected.setValuePosition(i, -1);
		long MAX=Long.MIN_VALUE;
		int selectedSetIndex=0;
		int selectedElementIndex=0;
		for (int i=0; i<this.sets.size(); i++) {
			Set set=(Set)this.sets.get(i);
			for (int j=0; j<set.size(); j++) {
				int pairsVisited=getPairsVisited(i, j);
				if (pairsVisited>MAX) {
					selectedSetIndex=i;
					selectedElementIndex=j;
					MAX=pairsVisited;
				}
			}
		}
		selected.setValuePosition(selectedSetIndex, selectedElementIndex);
		return selected;
	}

	private Combination copy(Combination selected) {
		Combination result=new Combination(selected.size());
		for (int i=0; i<selected.size(); i++) {
			result.setValuePosition(i, selected.getPosition(i));
		}
		return result;
	}

	/**
	 * 
	 * @param pptt
	 * @return null if there are no pair with weight 0
	 */
	private static /*@ nullable @*/Pair getPairWithWeight0(PairsTable[] pptt) {
		for (int i=0; i<pptt.length; i++) {
			Pair p=pptt[i].getPairWithWeight(0);
			if (p!=null) {
				return p;
			}
		}
		return null;
	}


	////@Override
	public String getName() {
		return "aetg";
	}

	////@Override
	public String getCredits() {
		return "Macario Polo and Beatriz Pôrez";
	}

}